home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / daemons / ipServer / tcpTimer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-19  |  11.3 KB  |  439 lines

  1. /* 
  2.  * tcpTimer.c --
  3.  *
  4.  *    The file contains routines to manage the 4 TCP connection timers.
  5.  *    The timers are described in detail in tcpTimer.h.
  6.  *
  7.  *    Based on 4.3BSD    @(#)tcp_timer.c    7.12 (Berkeley) 3/16/88
  8.  *
  9.  * Copyright 1987 Regents of the University of California
  10.  * All rights reserved.
  11.  * Permission to use, copy, modify, and distribute this
  12.  * software and its documentation for any purpose and without
  13.  * fee is hereby granted, provided that the above copyright
  14.  * notice appear in all copies.  The University of California
  15.  * makes no representations about the suitability of this
  16.  * software for any purpose.  It is provided "as is" without
  17.  * express or implied warranty.
  18.  */
  19.  
  20. #ifndef lint
  21. static char rcsid[] = "$Header: /sprite/src/daemons/ipServer/RCS/tcpTimer.c,v 1.6 89/07/23 17:35:18 nelson Exp $ SPRITE (Berkeley)";
  22. #endif not lint
  23.  
  24.  
  25. #include "sprite.h"
  26. #include "ipServer.h"
  27. #include "stat.h"
  28. #include "socket.h"
  29. #include "tcp.h"
  30. #include "tcpInt.h"
  31.  
  32. #include "time.h"
  33.  
  34. /*
  35.  * Number of times per second that TimeoutHandler is called. 
  36.  */
  37. #ifdef SPUR
  38. #define TIMEOUTS_PER_SEC    1
  39. #else
  40. #define TIMEOUTS_PER_SEC    4
  41. #endif
  42.  
  43. int tcpKeepLen = 1;    /* must be nonzero for 4.2 compat- XXX */
  44. int tcpKeepIdle = TCP_KEEP_TIME_IDLE;
  45. int tcpKeepIntvl = TCP_KEEP_TIME_INTVL;
  46. int tcpMaxIdle;
  47.  
  48. static int backoff[TCP_MAX_RXT_SHIFT+1] = {
  49.     1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64
  50. };
  51.  
  52. /*
  53.  * Forward declarations.
  54.  */
  55. static void    TimeoutHandler();
  56. static Boolean    ProcessTimers();
  57.  
  58.  
  59.  
  60. /*
  61.  *----------------------------------------------------------------------
  62.  *
  63.  * TCPTimerInit --
  64.  *
  65.  *    Sets up the TCP timeout handler so it is called at regular
  66.  *    intervals.
  67.  *
  68.  * Results:
  69.  *    None.
  70.  *
  71.  * Side effects:
  72.  *    A handler will be called at regular intervals.
  73.  *
  74.  *----------------------------------------------------------------------
  75.  */
  76.  
  77. void
  78. TCPTimerInit()
  79. {
  80.     Time interval;
  81.     Time_Divide(time_OneSecond, TIMEOUTS_PER_SEC, &interval);
  82.     (void)Fs_TimeoutHandlerCreate(interval,TRUE, TimeoutHandler, (ClientData)0);
  83. }
  84.  
  85. /*
  86.  *----------------------------------------------------------------------
  87.  *
  88.  * TimeoutHandler --
  89.  *
  90.  *    This routine handles 2 types of timeouts:
  91.  *     1) the fast timeout is needed for sending delayed ACKs, and
  92.  *     2) the slow timeout updates the timers in all active TCB's and
  93.  *        causes finite state machine actions if the timers expire.
  94.  *
  95.  * Results:
  96.  *    None.
  97.  *
  98.  * Side effects:
  99.  *    ACKs may be sent, timers are updated.
  100.  *
  101.  *----------------------------------------------------------------------
  102.  */
  103.  
  104. /*ARGSUSED*/
  105. static void
  106. TimeoutHandler(data, time)
  107.     ClientData    data;        /* Ignored. */
  108.     Time    time;        /* Ignored. */
  109. {
  110.     register TCPControlBlock *tcbPtr;
  111.     Sock_InfoPtr    sockPtr;
  112.     register int     i;
  113.     Boolean        processTimers;
  114.     static int         count = 0;
  115.  
  116.     stats.tcp.timerCalls++;
  117.  
  118.     /*
  119.      * The timers are processed once every second.
  120.      */
  121.     count++;
  122.     if (count == TIMEOUTS_PER_SEC/TIMER_UPDATE_RATE ||
  123.         (TIMEOUTS_PER_SEC/TIMER_UPDATE_RATE == 0)) {
  124.     count = 0;
  125.     processTimers = TRUE;
  126.     } else {
  127.     processTimers = FALSE;
  128.     }
  129.  
  130.     /*
  131.      * Go through all active TCP sockets and see if ACKs need to be
  132.      * sent and if the timers should be updated.
  133.      */
  134.     sockPtr = (Sock_InfoPtr) NULL;
  135.     while (TRUE) {
  136.     sockPtr = Sock_ScanList(TCP_PROTO_INDEX, sockPtr);
  137.     if (sockPtr == (Sock_InfoPtr) NULL) {
  138.         break;
  139.     }
  140.     tcbPtr = TCPSockToTCB(sockPtr);
  141.  
  142.     if (tcbPtr == (TCPControlBlock *) NULL) {
  143.         continue;
  144.     }
  145.  
  146.     /*
  147.      * At every timeout, process send an ACK if it was delayed.
  148.      */
  149.     if (tcbPtr->flags & TCP_DELAY_ACK) {
  150.  
  151.         tcbPtr->flags &= ~TCP_DELAY_ACK;
  152.         tcbPtr->flags |= TCP_ACK_NOW;
  153.         stats.tcp.delayAck++;
  154.         if (ips_Debug) {
  155.         fprintf(stderr, "TCP Timer: delay ack output\n");
  156.         }
  157.  
  158.         (void) TCPOutput(sockPtr, tcbPtr);
  159.     }
  160.  
  161.     if (processTimers) {
  162.  
  163.         /*
  164.          *  Update active timers.
  165.          */
  166.  
  167.         for (i = 0; i < TCP_NUM_TIMERS; i++) {
  168.         if (tcbPtr->timer[i] != 0) {
  169.             tcbPtr->timer[i]--;
  170.             if (tcbPtr->timer[i] == 0) {
  171.             if (!ProcessTimers(sockPtr, tcbPtr, i)) {
  172.                 goto tcbGone;
  173.             }
  174.             }
  175.         }
  176.         }
  177.         tcbPtr->idle++;
  178.         if (tcbPtr->rtt) {
  179.         tcbPtr->rtt++;
  180.         }
  181. tcbGone:
  182.         tcpISS += TCP_INIT_SEND_SEQ_INCR;
  183.     }
  184.     }
  185. }
  186.  
  187.  
  188.  
  189. /*
  190.  *----------------------------------------------------------------------
  191.  *
  192.  * ProcessTimers --
  193.  *
  194.  *    This routine is called once a second to update the 4 TCP
  195.  *    timers. The type of action taken depends on the timer. 
  196.  *
  197.  * Results:
  198.  *    TRUE    - the connection is still open and the tcb is valid.
  199.  *    FALSE    - the connection has been closed and the tcb is no longer
  200.  *          valid.
  201.  *
  202.  * Side effects:
  203.  *    The timer is updated. A connection may be dropped.
  204.  *
  205.  *----------------------------------------------------------------------
  206.  */
  207.  
  208. static Boolean
  209. ProcessTimers(sockPtr, tcbPtr, timer)
  210.     Sock_InfoPtr        sockPtr;    /* TCP socket. */
  211.     register TCPControlBlock    *tcbPtr;    /* TCB for the socket. */
  212.     int             timer;        /* Which timer. */
  213. {
  214.     register int rexmt;
  215.  
  216.     switch (timer) {
  217.  
  218.     /*
  219.      * 2 MSL timeout in shutdown went off.  If we're closed but
  220.      * still waiting for peer to close and connection has been idle
  221.      * too long, or if 2MSL time is up from TIME_WAIT, delete connection
  222.      * control block.  Otherwise, check again in a bit.
  223.      */
  224.     case TCP_TIMER_2MSL:
  225.         stats.tcp.mslTimeout++;
  226.         if (tcbPtr->state != TIME_WAIT &&
  227.         tcbPtr->idle <= tcpMaxIdle) {
  228.         tcbPtr->timer[TCP_TIMER_2MSL] = TCP_KEEP_TIME_INTVL;
  229.         } else {
  230.         TCPCloseConnection(sockPtr, tcbPtr);
  231.         return(FALSE);
  232.         }
  233.         break;
  234.  
  235.  
  236.     /*
  237.      * The retransmission timer went off.  Our message has not
  238.      * been ACKed within the retransmit interval.  Back off
  239.      * to a longer retransmit interval and retransmit one segment.
  240.      */
  241.     case TCP_TIMER_REXMT:
  242.         tcbPtr->rxtshift++;
  243.         if (tcbPtr->rxtshift > TCP_MAX_RXT_SHIFT) {
  244.             tcbPtr->rxtshift = TCP_MAX_RXT_SHIFT;
  245.         stats.tcp.timeoutDrop++;
  246.         TCPDropConnection(sockPtr, tcbPtr, GEN_TIMEOUT);
  247.         return(FALSE);
  248.         }
  249.         stats.tcp.rexmtTimeout++;
  250.         rexmt = ((tcbPtr->srtt >> 2) + tcbPtr->rttvar) >> 1;
  251.         rexmt *= backoff[tcbPtr->rxtshift];
  252.         TCP_TIMER_RANGESET(tcbPtr->rxtcur,
  253.             rexmt, TCP_MIN_REXMT_TIME, TCP_MAX_REXMT_TIME);
  254.         tcbPtr->timer[TCP_TIMER_REXMT] = tcbPtr->rxtcur;
  255.         /*
  256.          * If losing, let the lower level know and try for
  257.          * a better route.  Also, if we backed off this far,
  258.          * our smooth rtt estimate is probably bogus.  Clobber it
  259.          * so we'll take the next rtt measurement as our smooth rtt;
  260.          * move the current smooth rtt into rttvar to keep the current
  261.          * retransmit times until then.
  262.          */
  263.         if (tcbPtr->rxtshift > TCP_MAX_RXT_SHIFT / 4) {
  264.         Sock_BadRoute(sockPtr);
  265.         tcbPtr->rttvar += (tcbPtr->srtt >> 2);
  266.         tcbPtr->srtt = 0;
  267.         }
  268.         tcbPtr->send.next = tcbPtr->send.unAck;
  269.  
  270.         /*
  271.          * If timing a segment in this window, and we have already 
  272.          * gotten some timing estimate, stop the timer.
  273.          */
  274.         tcbPtr->rtt = 0;
  275.  
  276.         /*
  277.          * Close the congestion window down to one segment
  278.          * (we'll open it by one segment for each ack we get).
  279.          * Since we probably have a window's worth of unacked
  280.          * data accumulated, this "slow start" keeps us from
  281.          * dumping all that data as back-to-back packets (which
  282.          * might overwhelm an intermediate gateway).
  283.          *
  284.          * There are two phases to the opening: Initially we
  285.          * open by one mss on each ack.  This makes the window
  286.          * size increase exponentially with time.  If the
  287.          * window is larger than the path can handle, this
  288.          * exponential growth results in dropped packet(s)
  289.          * almost immediately.  To get more time between 
  290.          * drops but still "push" the network to take advantage
  291.          * of improving conditions, we switch from exponential
  292.          * to linear window opening at some threshhold size.
  293.          * For a threshhold, we use half the current window
  294.          * size, truncated to a multiple of the mss.
  295.          *
  296.          * (the minimum cwnd that will give us exponential
  297.          * growth is 2 mss.  We don't allow the threshhold
  298.          * to go below this.)
  299.          */
  300.         {
  301.         unsigned int win; 
  302.         win = MIN(tcbPtr->send.window, tcbPtr->send.congWindow) / 2 / 
  303.                 tcbPtr->maxSegSize;
  304.         if (win < 2) {
  305.             win = 2;
  306.         }
  307.         tcbPtr->send.congWindow = tcbPtr->maxSegSize;
  308.         tcbPtr->send.cwSizeThresh = win * tcbPtr->maxSegSize;
  309.         }
  310.         if (ips_Debug) {
  311.         fprintf(stderr, "TCP Timer: rexmt output\n");
  312.         }
  313.         (void) TCPOutput(sockPtr, tcbPtr);
  314.         break;
  315.  
  316.  
  317.     /*
  318.      * The persist timer has expired: see of the window is still closed.
  319.      * Force a byte to be output, if possible.
  320.      */
  321.     case TCP_TIMER_PERSIST:
  322.         stats.tcp.persistTimeout++;
  323.         TCPSetPersist(tcbPtr);
  324.         tcbPtr->force = 1;
  325.         if (ips_Debug) {
  326.         fprintf(stderr, "TCP Timer: persist output\n");
  327.         }
  328.         (void) TCPOutput(sockPtr, tcbPtr);
  329.         tcbPtr->force = 0;
  330.         break;
  331.  
  332.     /*
  333.      * Keep-alive timer went off: send something or drop the 
  334.      * connection if it has been idle for too long.
  335.      */
  336.     case TCP_TIMER_KEEP_ALIVE:
  337.         stats.tcp.keepTimeout++;
  338.         if (TCP_UNSYNCHRONIZED(tcbPtr->state)) {
  339.         stats.tcp.keepDrops++;
  340.         TCPDropConnection(sockPtr, tcbPtr, GEN_TIMEOUT);
  341.         return(FALSE);
  342.         }
  343.         if (Sock_IsOptionSet(sockPtr, NET_OPT_KEEP_ALIVE) &&
  344.         (tcbPtr->state == ESTABLISHED || tcbPtr->state == CLOSE_WAIT)) {
  345.  
  346.         if (tcbPtr->idle >= tcpKeepIdle + tcpMaxIdle) {
  347.                 stats.tcp.keepDrops++;
  348.             TCPDropConnection(sockPtr, tcbPtr, GEN_TIMEOUT);
  349.             return(FALSE);
  350.         }
  351.         /*
  352.          * Send a packet designed to force a response if the peer
  353.          * is up and reachable:  either an ACK if the connection
  354.          * is still alive, or an RESET if the peer has closed the
  355.          * connection due to timeout or reboot.  Using sequence
  356.          * number tcbPtr->send.unAck-1 causes the transmitted
  357.          * zero-length segment to lie outside the receive window;
  358.          * by the protocol spec, this requires the correspondent
  359.          * TCP to respond.
  360.          */
  361.         stats.tcp.keepProbe++;
  362.         TCPRespond(sockPtr, tcbPtr->templatePtr, 
  363.             tcbPtr->IPTemplatePtr, tcbPtr->recv.next - tcpKeepLen, 
  364.             tcbPtr->send.unAck - 1, 0);
  365.         tcbPtr->timer[TCP_TIMER_KEEP_ALIVE] = tcpKeepIntvl;
  366.         } else {
  367.         tcbPtr->timer[TCP_TIMER_KEEP_ALIVE] = tcpKeepIdle;
  368.         }
  369.         break;
  370.  
  371.     }
  372.     return(TRUE);
  373. }
  374.  
  375.  
  376. /*
  377.  *----------------------------------------------------------------------
  378.  *
  379.  * TCPSetPersist --
  380.  *
  381.  *    Starts or restarts the persistance timer.
  382.  *
  383.  * Results:
  384.  *    None.
  385.  *
  386.  * Side effects:
  387.  *    The timer is updated.
  388.  *
  389.  *----------------------------------------------------------------------
  390.  */
  391.  
  392. void
  393. TCPSetPersist(tcbPtr)
  394.     register TCPControlBlock *tcbPtr;
  395. {
  396.     register int t = ((tcbPtr->srtt >> 2) + tcbPtr->rttvar) >> 1;
  397.  
  398.     if (tcbPtr->timer[TCP_TIMER_REXMT] != 0) {
  399.      panic("TCPSetPersist REXMT timer != 0 (%d)\n",
  400.         tcbPtr->timer[TCP_TIMER_REXMT]);
  401.     }
  402.  
  403.     TCP_TIMER_RANGESET(tcbPtr->timer[TCP_TIMER_PERSIST],
  404.     t * backoff[tcbPtr->rxtshift],
  405.     TCP_MIN_PERSIST_TIME, TCP_MAX_PERSIST_TIME);
  406.  
  407.     if (tcbPtr->rxtshift < TCP_MAX_RXT_SHIFT) {
  408.     tcbPtr->rxtshift++;
  409.     }
  410. }
  411.  
  412.  
  413. /*
  414.  *----------------------------------------------------------------------
  415.  *
  416.  * TCPCancelTimers --
  417.  *
  418.  *    Cancel all timers for a TCP control block.
  419.  *
  420.  * Results:
  421.  *    None.
  422.  *
  423.  * Side effects:
  424.  *    The timers are cancelled.
  425.  *
  426.  *----------------------------------------------------------------------
  427.  */
  428.  
  429. void
  430. TCPCancelTimers(tcbPtr)
  431.     register TCPControlBlock *tcbPtr;
  432. {
  433.     register int i;
  434.  
  435.     for (i = 0; i < TCP_NUM_TIMERS; i++) {
  436.     tcbPtr->timer[i] = 0;
  437.     }
  438. }
  439.